package org.fast.easy.framework.web.printer;

import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.condition.PathPatternsRequestCondition;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import java.lang.reflect.Method;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author llq
 * @Description ApplicationListener实现类
 */

@Slf4j
@Component
public class ControllerPrinter implements ApplicationContextAware {

    private ApplicationContext context;
    @Value("${logging.level.org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping:}")
    private String restLoggingLevel;
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        this.context = applicationContext;
    }

    // ANSI转义码
    public static final String ANSI_RESET = "\u001B[0m";
    public static final String ANSI_RED = "\u001B[31m";
    public static final String ANSI_GREEN = "\u001B[32m";
    public static final String ANSI_YELLOW = "\u001B[33m";
    public static final String ANSI_BLUE = "\u001B[34m";

    @PostConstruct
    public void printerListEndpoints() {
        if(!"trace".equals(restLoggingLevel)) {
            LinkedHashMap<String, List<String>> restList = new LinkedHashMap<>();
            for (String beanName : context.getBeanDefinitionNames()) {
                if (beanName.endsWith("Controller")) {
                    Class<?> controllerClass = context.getType(beanName);
                    if (controllerClass.isAnnotationPresent(RestController.class)) {
                        // 注解存在的逻辑处理
                        List<String> endpoints = new ArrayList<>();
                        for (Method method : controllerClass.getDeclaredMethods()) {
                            if (method.isAnnotationPresent(RequestMapping.class) ||
                                    method.isAnnotationPresent(GetMapping.class) ||
                                    method.isAnnotationPresent(PostMapping.class) ||
                                    method.isAnnotationPresent(PutMapping.class) ||
                                    method.isAnnotationPresent(DeleteMapping.class)) {
                                String endpoint = buildEndpointPath(controllerClass, method);
                                if (StringUtils.isNotBlank(endpoint)) {
                                    endpoints.add(endpoint);
                                }
                            }
                        }
                        if (endpoints.size() > 0) {
                            // 使用默认排序规则
                            Collections.sort(endpoints);
                            restList.put(beanName, endpoints);
                        }
                    }
                }
            }
            printInfo(restList);
        }else{
            System.out.println(ANSI_BLUE + "========================> Rest Api Mappings<========================" + ANSI_RESET);
        }
    }

    private void printInfo(LinkedHashMap<String,List<String>> restList){
        if(restList.size() > 0) {
            System.out.println(ANSI_BLUE + "============> Rest Api Start<============" + ANSI_RESET);
            AtomicInteger i = new AtomicInteger(1);
            for(Map.Entry<String,List<String>> entry : restList.entrySet()){
                System.out.println(ANSI_GREEN + "Controller: " + entry.getKey() + ANSI_RESET);
                AtomicInteger j = new AtomicInteger(1);
                for(String endpoint : entry.getValue()){
                    System.out.println((i.getAndIncrement()) +"\t"+ANSI_GREEN + (j.getAndIncrement()) + ": " + ANSI_RESET + endpoint);
                }
            }
            System.out.println(ANSI_BLUE + "============> Rest Api Start<============" + ANSI_RESET);
        }

    }



    private String buildEndpointPath(Class<?> controllerClass, Method method) {
        // 这里根据实际情况构建完整的路径，比如考虑@RequestMapping注解在类和方法上
        RequestMapping classMapping = controllerClass.getAnnotation(RequestMapping.class);
        RequestMapping methodMapping = method.getAnnotation(RequestMapping.class);
        GetMapping getMapping = method.getAnnotation(GetMapping.class);
        PostMapping postMapping = method.getAnnotation(PostMapping.class);
        PutMapping putMapping = method.getAnnotation(PutMapping.class);
        DeleteMapping deleteMapping = method.getAnnotation(DeleteMapping.class);

        StringBuilder info = new StringBuilder();
        StringBuilder path = new StringBuilder();
        if (classMapping != null && classMapping.value().length > 0) {
            path.append(classMapping.value()[0]);
        }
        if (methodMapping != null ) {
            if (methodMapping.value().length > 0) {
                path.append(methodMapping.value()[0]);
            }
            info.append("[] ");
        } else if (getMapping != null ) {
            if (getMapping.value().length > 0) {
                path.append(getMapping.value()[0]);
            }
            info.append("[").append(ANSI_YELLOW).append("GET").append(ANSI_RESET).append("] ");
        } else if (postMapping != null ) {
            if (postMapping.value().length > 0) {
                path.append(postMapping.value()[0]);
            }
            info.append("[").append(ANSI_YELLOW).append("POST").append(ANSI_RESET).append("] ");
        } else if (putMapping != null ) {
            if (putMapping.value().length > 0) {
                path.append(putMapping.value()[0]);
            }
            info.append("[").append(ANSI_YELLOW).append("PUT").append(ANSI_RESET).append("] ");
        } else if (deleteMapping != null  ) {
            if (deleteMapping.value().length > 0) {
                path.append(deleteMapping.value()[0]);
            }
            info.append("[").append(ANSI_YELLOW).append("DELETE").append(ANSI_RESET).append("] ");
        }
        if(info.length() > 0) {
            info.append(path);
        }
        return info.toString();
    }
}
